package cn.weakup.thread.lock;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * @author Dawn
 * @version 1.0.0
 * @desc 乐观读锁，在读多写少的场景下性能更优于ReentrantReadWriteLock
 * @date 2022/5/9
 */
public class StampedLockDemo {
    public static ExecutorService executor = new ThreadPoolExecutor(8, 16, 10,
            TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.AbortPolicy());
    private static final StampedLock stampedLock = new StampedLock();

    private static double x, y;

    public static void main(String[] args) {

        MyCacheLock myCache = new MyCacheLock();
        x = 0.2;
        y = 0.4;

        // 多个线程同时进行读写,保证写入的时候没有其他线程插队
        // 五个线程在写  线程是CPU调度的
        for (int i = 1; i <= 10; i++) {
            // 模拟一次写入
            if(i == 5) {

                new Thread(()->{
                    long stamp = stampedLock.writeLock();
                    try {
                        System.out.println("变更x开始");
                        x++;
                        System.out.println("变更x完毕");
                    } finally {
                        stampedLock.unlockWrite(stamp);
                    }
                }).start();
            }

            // 多次读取
            new Thread(()->{
                System.out.println(getArea());
            }).start();
        }
    }

    static double getArea() {
        // 获得一个乐观读锁
        long stamp = stampedLock.tryOptimisticRead();
        // 将两个字段读入本地局部变量
        double currentX = x, currentY = y;
        // 检查发出乐观读锁后同时是否有其他写锁发生？
        if (!stampedLock.validate(stamp)) {
            //如果没有，我们再次获得一个读悲观锁
            stamp = stampedLock.readLock();
            try {
                // 将两个字段读入本地局部变量
                currentX = x;
                // 将两个字段读入本地局部变量
                currentY = y;
            } finally {
                stampedLock.unlockRead(stamp);
            }
        }
        return currentX * currentY;
    }
}
